Public Class cls_Figura
    Private FigCuad As Icono
    Private ESI As Posicion
    Private Alto As Integer = 20
    Private Ancho As Integer = 16
    Private Maya(Ancho, Alto) As Integer
    Private Color1 As Color
    Private Color2 As Color
    Private Color3 As Color


#Region " Estructuras & Enums "

    Public Structure Posicion
        Dim PosX As Integer
        Dim PosY As Integer
    End Structure

    Public Structure Icono
        Dim TF As Figura
        Dim Pos As PosFig
        Dim P1 As Posicion
        Dim P2 As Posicion
        Dim P3 As Posicion
        Dim P4 As Posicion
    End Structure

    Public Enum Figura As Integer
        Cuadrado = 1
        FlitDer = 2
        FlitIzq = 3
        EleDer = 4
        EleIzq = 5
        Barra = 6
        Piram = 7
    End Enum

    Public Enum Direccion As Integer
        Arriba = 1
        Abajo = 2
        Derecha = 3
        Izquierda = 4
    End Enum

    Public Enum PosFig As Integer
        Parado = 1
        AcostadoBocaArriba = 2
        DeCabeza = 3
        AcostadoBocaAbajo = 4
    End Enum

#End Region

#Region " Propiedades "

    Public ReadOnly Property TipoFigura() As Figura
        Get
            Return FigCuad.TF
        End Get
    End Property

#End Region

#Region " Constructor "

    Sub New(ByVal TipoFig As Figura, ByVal EzSupIzq As Posicion, ByRef Matriz(,) As Integer, ByVal Col1 As Color, ByVal Col2 As Color, ByVal Col3 As Color)

        FigCuad.TF = TipoFig
        FigCuad.Pos = PosFig.Parado
        ESI = EzSupIzq
        Maya = Matriz
        Color1 = Col1
        Color2 = Col2
        Color3 = Col3
        DibujaFigura()

    End Sub

#End Region

#Region " Funciones Publicas "

    Public Function TeclaDir(ByVal Direct As Direccion) As Boolean

        Select Case Direct
            Case Direccion.Arriba
                Dim Icon As Icono
                Dim Intento As Integer = 0

                Icon = GiraPosFig()
                Do While PosOcupada(Direct, Icon) And Intento < 2
                    ESI.PosX -= 1
                    Icon.P1.PosX -= 1
                    Icon.P2.PosX -= 1
                    Icon.P3.PosX -= 1
                    Icon.P4.PosX -= 1
                    Intento += 1
                Loop
                If Not PosOcupada(Direct, Icon) Then
                    FigCuad = Icon
                End If
            Case Direccion.Abajo
                If PosOcupada(Direct, FigCuad) = False Then
                    ESI.PosY += 1
                    FigCuad.P1.PosY += 1
                    FigCuad.P2.PosY += 1
                    FigCuad.P3.PosY += 1
                    FigCuad.P4.PosY += 1
                Else
                    ' Descargamos la figura en la maya del tetris
                    Maya(FigCuad.P1.PosX - 2, FigCuad.P1.PosY - 1) = 1
                    Maya(FigCuad.P2.PosX - 2, FigCuad.P2.PosY - 1) = 1
                    Maya(FigCuad.P3.PosX - 2, FigCuad.P3.PosY - 1) = 1
                    Maya(FigCuad.P4.PosX - 2, FigCuad.P4.PosY - 1) = 1
                    Return True
                End If
            Case Direccion.Derecha
                If Not PosOcupada(Direct, FigCuad) Then
                    ESI.PosX += 1
                    FigCuad.P1.PosX += 1
                    FigCuad.P2.PosX += 1
                    FigCuad.P3.PosX += 1
                    FigCuad.P4.PosX += 1
                End If
            Case Direccion.Izquierda
                If PosOcupada(Direct, FigCuad) = False Then
                    ESI.PosX -= 1
                    FigCuad.P1.PosX -= 1
                    FigCuad.P2.PosX -= 1
                    FigCuad.P3.PosX -= 1
                    FigCuad.P4.PosX -= 1
                End If
        End Select

        Return False
    End Function

    Public Function CabeFigura() As Boolean
        If MayaOcupada(FigCuad) Then
            Return False
        End If
        Return True
    End Function

#End Region

#Region " Funciones Privadas "

    Public Sub Print(ByVal g As Graphics)
        Dim cuad As cls_Cuadro = New cls_Cuadro(1, 1, Color1, Color2, Color3)

        ' Dibujamos los 4 cuadrados de la figura

        cuad.SetPos(FigCuad.P1.PosX, FigCuad.P1.PosY)
        cuad.Print(g)

        cuad.SetPos(FigCuad.P2.PosX, FigCuad.P2.PosY)
        cuad.Print(g)

        cuad.SetPos(FigCuad.P3.PosX, FigCuad.P3.PosY)
        cuad.Print(g)

        cuad.SetPos(FigCuad.P4.PosX, FigCuad.P4.PosY)
        cuad.Print(g)

    End Sub

    Private Function PosOcupada(ByVal Direct As Direccion, ByVal F As Icono) As Boolean
        Dim icon As Icono = F

        Select Case Direct
            Case Direccion.Arriba
                If ExedeParedes(Direccion.Arriba, icon) Then Return True
                If ExecePiso(Direct, icon) Then Return True
                If MayaOcupada(icon) Then Return True
            Case Direccion.Derecha
                If ExedeParedes(Direct, F) Then Return True
                icon.P1.PosX += 1
                icon.P2.PosX += 1
                icon.P3.PosX += 1
                icon.P4.PosX += 1
                If MayaOcupada(icon) Then Return True
            Case Direccion.Izquierda
                If ExedeParedes(Direct, F) Then Return True
                icon.P1.PosX -= 1
                icon.P2.PosX -= 1
                icon.P3.PosX -= 1
                icon.P4.PosX -= 1
                If MayaOcupada(icon) Then Return True
            Case Direccion.Abajo
                If ExecePiso(Direct, F) Then Return True
                icon.P1.PosY += 1
                icon.P2.PosY += 1
                icon.P3.PosY += 1
                icon.P4.PosY += 1
                If MayaOcupada(icon) Then Return True
        End Select
        Return False

    End Function

    Private Function ExedeParedes(ByVal D As Direccion, ByVal I As Icono) As Boolean

        Select Case D
            Case Direccion.Arriba
                If I.P1.PosX > Ancho Then Return True
                If I.P2.PosX > Ancho Then Return True
                If I.P3.PosX > Ancho Then Return True
                If I.P4.PosX > Ancho Then Return True
                If I.P1.PosX < 2 Then Return True
                If I.P2.PosX < 2 Then Return True
                If I.P3.PosX < 2 Then Return True
                If I.P4.PosX < 2 Then Return True
            Case Direccion.Izquierda
                If (I.P1.PosX - 1) < 2 Then Return True
                If (I.P2.PosX - 1) < 2 Then Return True
                If (I.P3.PosX - 1) < 2 Then Return True
                If (I.P4.PosX - 1) < 2 Then Return True
            Case Direccion.Derecha
                If (I.P1.PosX + 1) > Ancho Then Return True
                If (I.P2.PosX + 1) > Ancho Then Return True
                If (I.P3.PosX + 1) > Ancho Then Return True
                If (I.P4.PosX + 1) > Ancho Then Return True
        End Select
        Return False

    End Function

    Private Function ExecePiso(ByVal D As Direccion, ByVal I As Icono) As Boolean

        Select Case D
            Case Direccion.Arriba
                If I.P1.PosY > Alto Then Return True
                If I.P2.PosY > Alto Then Return True
                If I.P3.PosY > Alto Then Return True
                If I.P4.PosY > Alto Then Return True
            Case Direccion.Abajo
                If (I.P1.PosY + 1) > Alto Then Return True
                If (I.P2.PosY + 1) > Alto Then Return True
                If (I.P3.PosY + 1) > Alto Then Return True
                If (I.P4.PosY + 1) > Alto Then Return True
        End Select
        Return False

    End Function

    Private Function MayaOcupada(ByVal I As Icono) As Boolean

        If Maya(I.P1.PosX - 2, I.P1.PosY - 1) = 1 Then Return True
        If Maya(I.P2.PosX - 2, I.P2.PosY - 1) = 1 Then Return True
        If Maya(I.P3.PosX - 2, I.P3.PosY - 1) = 1 Then Return True
        If Maya(I.P4.PosX - 2, I.P4.PosY - 1) = 1 Then Return True
        Return False

    End Function

    Private Function SetPos(ByVal x As Integer, ByVal y As Integer) As Posicion
        Dim P As Posicion

        P.PosX = x
        P.PosY = y
        Return P

    End Function

    Private Function GiraPosFig() As Icono
        Dim Icon As Icono

        Select Case FigCuad.Pos
            Case PosFig.Parado
                Icon = CalculaPosiciones(FigCuad.TF, PosFig.AcostadoBocaArriba)
                Icon.Pos = PosFig.AcostadoBocaArriba
            Case PosFig.AcostadoBocaArriba
                Icon = CalculaPosiciones(FigCuad.TF, PosFig.DeCabeza)
                Icon.Pos = PosFig.DeCabeza
            Case PosFig.DeCabeza
                Icon = CalculaPosiciones(FigCuad.TF, PosFig.AcostadoBocaAbajo)
                Icon.Pos = PosFig.AcostadoBocaAbajo
            Case PosFig.AcostadoBocaAbajo
                Icon = CalculaPosiciones(FigCuad.TF, PosFig.Parado)
                Icon.Pos = PosFig.Parado
        End Select
        Return Icon

    End Function

    Private Sub DibujaFigura()
        FigCuad = CalculaPosiciones(FigCuad.TF, FigCuad.Pos)
    End Sub

    Private Function CalculaPosiciones(ByVal MyFig As Figura, ByVal MyPos As PosFig) As Icono
        Dim Icon As Icono = FigCuad

        Select Case MyFig

            Case Figura.Cuadrado
                Select Case MyPos
                    Case PosFig.Parado, PosFig.DeCabeza, PosFig.AcostadoBocaArriba, PosFig.AcostadoBocaAbajo
                        Icon.P1 = SetPos(ESI.PosX, ESI.PosY)
                        Icon.P2 = SetPos(ESI.PosX, ESI.PosY + 1)
                        Icon.P3 = SetPos(ESI.PosX + 1, ESI.PosY)
                        Icon.P4 = SetPos(ESI.PosX + 1, ESI.PosY + 1)
                End Select

            Case Figura.FlitDer
                Select Case MyPos
                    Case PosFig.Parado, PosFig.DeCabeza
                        Icon.P1 = SetPos(ESI.PosX, ESI.PosY)
                        Icon.P2 = SetPos(ESI.PosX, ESI.PosY + 1)
                        Icon.P3 = SetPos(ESI.PosX + 1, ESI.PosY + 1)
                        Icon.P4 = SetPos(ESI.PosX + 1, ESI.PosY + 2)
                    Case PosFig.AcostadoBocaArriba, PosFig.AcostadoBocaAbajo
                        Icon.P1 = SetPos(ESI.PosX, ESI.PosY + 1)
                        Icon.P2 = SetPos(ESI.PosX + 1, ESI.PosY)
                        Icon.P3 = SetPos(ESI.PosX + 1, ESI.PosY + 1)
                        Icon.P4 = SetPos(ESI.PosX + 2, ESI.PosY)
                End Select


            Case Figura.FlitIzq
                Select Case MyPos
                    Case PosFig.Parado, PosFig.DeCabeza
                        Icon.P1 = SetPos(ESI.PosX, ESI.PosY + 1)
                        Icon.P2 = SetPos(ESI.PosX, ESI.PosY + 2)
                        Icon.P3 = SetPos(ESI.PosX + 1, ESI.PosY)
                        Icon.P4 = SetPos(ESI.PosX + 1, ESI.PosY + 1)
                    Case PosFig.AcostadoBocaArriba, PosFig.AcostadoBocaAbajo
                        Icon.P1 = SetPos(ESI.PosX, ESI.PosY)
                        Icon.P2 = SetPos(ESI.PosX + 1, ESI.PosY)
                        Icon.P3 = SetPos(ESI.PosX + 1, ESI.PosY + 1)
                        Icon.P4 = SetPos(ESI.PosX + 2, ESI.PosY + 1)
                End Select


            Case Figura.EleDer
                Select Case MyPos
                    Case PosFig.Parado
                        Icon.P1 = SetPos(ESI.PosX, ESI.PosY)
                        Icon.P2 = SetPos(ESI.PosX, ESI.PosY + 1)
                        Icon.P3 = SetPos(ESI.PosX, ESI.PosY + 2)
                        Icon.P4 = SetPos(ESI.PosX + 1, ESI.PosY + 2)
                    Case PosFig.AcostadoBocaArriba
                        Icon.P1 = SetPos(ESI.PosX, ESI.PosY + 1)
                        Icon.P2 = SetPos(ESI.PosX + 1, ESI.PosY + 1)
                        Icon.P3 = SetPos(ESI.PosX + 2, ESI.PosY)
                        Icon.P4 = SetPos(ESI.PosX + 2, ESI.PosY + 1)
                    Case PosFig.DeCabeza
                        Icon.P1 = SetPos(ESI.PosX, ESI.PosY)
                        Icon.P2 = SetPos(ESI.PosX + 1, ESI.PosY)
                        Icon.P3 = SetPos(ESI.PosX + 1, ESI.PosY + 1)
                        Icon.P4 = SetPos(ESI.PosX + 1, ESI.PosY + 2)
                    Case PosFig.AcostadoBocaAbajo
                        Icon.P1 = SetPos(ESI.PosX, ESI.PosY)
                        Icon.P2 = SetPos(ESI.PosX, ESI.PosY + 1)
                        Icon.P3 = SetPos(ESI.PosX + 1, ESI.PosY)
                        Icon.P4 = SetPos(ESI.PosX + 2, ESI.PosY)
                End Select


            Case Figura.EleIzq
                Select Case MyPos
                    Case PosFig.Parado
                        Icon.P1 = SetPos(ESI.PosX, ESI.PosY + 2)
                        Icon.P2 = SetPos(ESI.PosX + 1, ESI.PosY)
                        Icon.P3 = SetPos(ESI.PosX + 1, ESI.PosY + 1)
                        Icon.P4 = SetPos(ESI.PosX + 1, ESI.PosY + 2)
                    Case PosFig.AcostadoBocaArriba
                        Icon.P1 = SetPos(ESI.PosX, ESI.PosY)
                        Icon.P2 = SetPos(ESI.PosX + 1, ESI.PosY)
                        Icon.P3 = SetPos(ESI.PosX + 2, ESI.PosY)
                        Icon.P4 = SetPos(ESI.PosX + 2, ESI.PosY + 1)
                    Case PosFig.DeCabeza
                        Icon.P1 = SetPos(ESI.PosX, ESI.PosY)
                        Icon.P2 = SetPos(ESI.PosX, ESI.PosY + 1)
                        Icon.P3 = SetPos(ESI.PosX, ESI.PosY + 2)
                        Icon.P4 = SetPos(ESI.PosX + 1, ESI.PosY)
                    Case PosFig.AcostadoBocaAbajo
                        Icon.P1 = SetPos(ESI.PosX, ESI.PosY)
                        Icon.P2 = SetPos(ESI.PosX, ESI.PosY + 1)
                        Icon.P3 = SetPos(ESI.PosX + 1, ESI.PosY + 1)
                        Icon.P4 = SetPos(ESI.PosX + 2, ESI.PosY + 1)
                End Select


            Case Figura.Barra
                Select Case MyPos
                    Case PosFig.Parado, PosFig.DeCabeza
                        Icon.P1 = SetPos(ESI.PosX, ESI.PosY)
                        Icon.P2 = SetPos(ESI.PosX, ESI.PosY + 1)
                        Icon.P3 = SetPos(ESI.PosX, ESI.PosY + 2)
                        Icon.P4 = SetPos(ESI.PosX, ESI.PosY + 3)
                    Case PosFig.AcostadoBocaArriba, PosFig.AcostadoBocaAbajo
                        Icon.P1 = SetPos(ESI.PosX - 1, ESI.PosY)
                        Icon.P2 = SetPos(ESI.PosX, ESI.PosY)
                        Icon.P3 = SetPos(ESI.PosX + 1, ESI.PosY)
                        Icon.P4 = SetPos(ESI.PosX + 2, ESI.PosY)
                End Select


            Case Figura.Piram
                Select Case MyPos
                    Case PosFig.Parado
                        Icon.P1 = SetPos(ESI.PosX, ESI.PosY)
                        Icon.P2 = SetPos(ESI.PosX, ESI.PosY + 1)
                        Icon.P3 = SetPos(ESI.PosX, ESI.PosY + 2)
                        Icon.P4 = SetPos(ESI.PosX + 1, ESI.PosY + 1)
                    Case PosFig.AcostadoBocaArriba
                        Icon.P1 = SetPos(ESI.PosX, ESI.PosY + 1)
                        Icon.P2 = SetPos(ESI.PosX + 1, ESI.PosY)
                        Icon.P3 = SetPos(ESI.PosX + 1, ESI.PosY + 1)
                        Icon.P4 = SetPos(ESI.PosX + 2, ESI.PosY + 1)
                    Case PosFig.DeCabeza
                        Icon.P1 = SetPos(ESI.PosX, ESI.PosY + 1)
                        Icon.P2 = SetPos(ESI.PosX + 1, ESI.PosY)
                        Icon.P3 = SetPos(ESI.PosX + 1, ESI.PosY + 1)
                        Icon.P4 = SetPos(ESI.PosX + 1, ESI.PosY + 2)
                    Case PosFig.AcostadoBocaAbajo
                        Icon.P1 = SetPos(ESI.PosX, ESI.PosY)
                        Icon.P2 = SetPos(ESI.PosX + 1, ESI.PosY)
                        Icon.P3 = SetPos(ESI.PosX + 1, ESI.PosY + 1)
                        Icon.P4 = SetPos(ESI.PosX + 2, ESI.PosY)
                End Select

        End Select

        Return Icon

    End Function

#End Region

End Class
